﻿using System;
using MLog.Core;
using MLog.Core.Appender;
using UnityEngine;

namespace MLog {
    public class MLog {
        private const  int  Uninitialize      = 0;
        private const  int  Initializing      = 1;
        private const  int  Initialized       = 2;
        private static int  _initializedState = Uninitialize;
        private static bool _destroyed;

        private static readonly CachedLoggerFactory SubstFactory =
            new CachedLoggerFactory(new SubstituteLoggerFactory());

        private static ILoggerFactory LoggerFactory { set; get; }

        public static void Initialize(ILoggerFactory loggerFactory = null) {
            lock (typeof(MLog)) {
                if (_initializedState != Uninitialize) {
                    Debug.LogWarning("MLog: already initialize.");
                    return;
                }

                _initializedState = Initializing;

                LoggerConfiguration.Initialize(ConfigurationInitialized);
                LoggerFactory = loggerFactory;
            }
        }

        private static void ConfigurationInitialized() {
            _initializedState = Initialized;

            foreach (var logger in SubstFactory.GetCachedLoggers()) {
                var substLogger = (SubstituteLogger) logger;
                substLogger.Delegate = GetLogger(substLogger.Name);
            }

            ReplayEvent();
        }

        private static void ReplayEvent() {
            var factory = SubstFactory.DelegateFactory as SubstituteLoggerFactory;
            if (factory != null) {
                var events = factory.EventQueue;
                while (events.Count > 0) {
                    var @event = events.Dequeue();
                    ((BaseLogger) @event.Source).LogEvent(@event);
                }
            }
        }

        public static ILoggerFactory GetLoggerFactory() {
            if (_initializedState != Initialized) {
                return SubstFactory;
            }

            return LoggerFactory ?? (LoggerFactory = new CachedLoggerFactory(new StandardLoggerFactory()));
        }

        public static ILogger GetLogger(string name) {
            return GetLoggerFactory().GetLogger(name);
        }

        public static ILogger GetLogger(Type type) {
            return GetLogger(type.FullName);
        }

        public static void Destroy() {
            lock (typeof(MLog)) {
                if (_destroyed) {
                    Debug.LogWarning("MLog: already destroy.");
                    return;
                }

                Workers.Clear();
                var factory = LoggerFactory as CachedLoggerFactory;
                if (factory != null) factory.Clear();

                _destroyed = true;
            }
        }
    }
}